package net.chrisrichardson.ec2deployer.applications

import net.chrisrichardson.ec2deployer.core.EC2Server
import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.util.FileBasedTemplate
import net.chrisrichardson.ec2deployer.cluster.AppServerTier
import net.chrisrichardson.ec2deployer.cluster.ClusterSpec
import net.chrisrichardson.ec2deployer.core.AWSProperties
import net.chrisrichardson.ec2deployer.core.S3Synchronizer

class ApacheServerTest extends GroovyTestCase {

    def host
    def tomcatServer
    def ApacheServer apacheServer

    MockFor mockForTomcatServer
    MockFor  mockForApacheHost

    def webApp1
    def webApp2
    MockFor mockFileBasedTemplate
    def expectedApacheConf = "expectedApacheConf"
    MockFor mockAppServerTier
    ClusterSpec spec
    MockFor mockS3Synchronizer

    def void setUp() {
        webApp1 = new WebApp("/foo", "foo")
        webApp2 = new WebApp("/bar", "bar")

        mockForTomcatServer = new MockFor(TomcatServer)
        mockAppServerTier = new MockFor(AppServerTier)

        mockForApacheHost = new MockFor(EC2Server)
        mockFileBasedTemplate = new MockFor(FileBasedTemplate)
        this.mockS3Synchronizer = new MockFor(S3Synchronizer)

        this.spec = new ClusterSpec()

    }

    public static void assertEquals(expected, actual) {
        if (!expected.equals(actual)) {
            fail "Expected <${expected}> but got <${actual}>"
        }
    }

    public void testConfigure() {

        setExpectationsForConfigureWithoutSsl()
        setExpectationsForConfigureWithoutSsl2();
        mockFileBasedTemplate.use {
            mockForApacheHost.use {
                mockForTomcatServer.use {
                    mockAppServerTier.use {
                        host = new EC2Server();
                        def appServerTier = new AppServerTier()
                        tomcatServer = new TomcatServer()

                        apacheServer = new ApacheServer(host, appServerTier, spec)

                        apacheServer.configure()
                    }
                }

            }
        }
    }

    public void testConfigureWithExtraConf() {
        spec.extraHttpConf("Here is some")

        mockForApacheHost.demand.ssh {String command, String conf ->
            assertEquals "cat > /etc/httpd/conf.d/extras.conf", command
            assertEquals("Here is some", conf)
        }


        setExpectationsForConfigureWithoutSsl()
        setExpectationsForConfigureWithoutSsl2();
        mockFileBasedTemplate.use {
            mockForApacheHost.use {
                mockForTomcatServer.use {
                    mockAppServerTier.use {
                        host = new EC2Server();
                        def appServerTier = new AppServerTier()
                        tomcatServer = new TomcatServer()

                        apacheServer = new ApacheServer(host, appServerTier, spec)

                        apacheServer.configure()
                    }
                }

            }
        }
    }

    void setExpectationsForConfigureWithoutSsl() {
        mockForTomcatServer.demand.getActualContexts {["foo", "bar"]}

        mockFileBasedTemplate.demand.process {name, params ->
            assertEquals "/templates/httpd.conf", name
            assertEquals(["tomcats": [tomcatServer]], params)
            expectedApacheConf
        }

        mockForApacheHost.demand.ssh {String command, String conf ->
            assertEquals "cat > /etc/httpd/conf/httpd.conf", command
            assertEquals(expectedApacheConf, conf)
        }

        mockFileBasedTemplate.demand.process {name, params ->
            assertEquals "/templates/cluster.conf", name
            assertEquals(["tomcats": [tomcatServer]], params)
            expectedApacheConf
        }

        mockForApacheHost.demand.ssh {String command, conf ->
            assertEquals "cat > /etc/httpd/conf.d/cluster.conf", command
            assertEquals(expectedApacheConf, conf)
        }
    }

    void setExpectationsForConfigureWithoutSsl2() {
        mockForApacheHost.demand.ssh {String restartCommand ->
            assertEquals "/usr/sbin/apachectl restart", restartCommand
        }
        mockForApacheHost.demand.ssh {String wgetCommand ->
            assertEquals "wget --spider --tries=10 --retry-connrefused --waitretry=10 http://localhost:80/foo", wgetCommand
        }

        3.times {mockAppServerTier.demand.getTomcats { [tomcatServer] }}
    }

    public void testConfigureWithSsl() {
        spec.ssl("/foo/mykeyfile.key", "/foo/mycertfile.cert")

        setExpectationsForConfigureWithoutSsl()

        mockForTomcatServer.demand.getActualContexts {["foo", "bar"]}

        mockForApacheHost.demand.ssh {command  ->
            assertEquals "yum -y install mod_ssl", command
        }

        mockFileBasedTemplate.demand.process {name, params ->
            assertEquals "/templates/ssl.conf", name
            assertEquals(["tomcats": [tomcatServer]], params)
            "expectedSslConf"
        }


        mockForApacheHost.demand.ssh {String command, String conf ->
            assertEquals "cat > /etc/httpd/conf.d/ssl.conf", command
            assertEquals "expectedSslConf", conf
        }

        mockForApacheHost.demand.scp {String from, String to ->
            assertEquals "/foo/mykeyfile.key", from
            assertEquals "/etc/httpd/conf/my.key", to
        }

        mockForApacheHost.demand.scp {String from, String to ->
            assertEquals "/foo/mycertfile.cert", from
            assertEquals "/etc/httpd/conf/my.cert", to
        }

        2.times{mockAppServerTier.demand.getTomcats { [tomcatServer] }}

        mockForApacheHost.demand.ssh {String command ->
            assertEquals "chmod 0400 /etc/httpd/conf/my.key", command
        }
        mockForApacheHost.demand.ssh {String command ->
            assertEquals "chmod 0400 /etc/httpd/conf/my.cert", command
        }

        setExpectationsForConfigureWithoutSsl2()

        mockForApacheHost.demand.ssh {String wgetCommand ->
            assertEquals "wget --no-check-certificate --spider --tries=10 --retry-connrefused --waitretry=10 https://localhost:443/foo", wgetCommand
        }

        mockFileBasedTemplate.use {
            mockForApacheHost.use {
                mockForTomcatServer.use {
                    mockAppServerTier.use {
                        host = new EC2Server();
                        def appServerTier = new AppServerTier()
                        tomcatServer = new TomcatServer()

                        apacheServer = new ApacheServer(host, appServerTier, spec)

                        apacheServer.configure()
                    }
                }

            }
        }
    }

    public void testConfigureWithStaticContent() {

        spec.staticContent("/usr/home/foostaticontent", "foocachebucket")
        setExpectationsForConfigureWithoutSsl()

        mockForApacheHost.demand.getAwsProperties { new AWSProperties(new Properties())    }

        mockS3Synchronizer.demand.uploadToS3 { wars, bucketPrefix, bucket ->
            assertEquals "", bucketPrefix
            assertEquals (["/usr/home/foostaticontent"], wars)
            assertEquals "foocachebucket", bucket
        }

        mockS3Synchronizer.demand.downloadFromS3 {host, bucketPrefix, bucket, dir ->
            assertEquals "", bucketPrefix
            assertEquals "foocachebucket", bucket
            assertEquals "/var/tmp/staticcontent", dir
        }

        mockForApacheHost.demand.ssh {String cmd ->
            assertEquals "rsync --del -u -v -r  /var/tmp/staticcontent/foostaticontent/ /var/www/html", cmd
        }

        setExpectationsForConfigureWithoutSsl2();

        mockForApacheHost.demand.ssh {String wgetCommand ->
              assertEquals "wget --spider --tries=10 --retry-connrefused --waitretry=10 http://localhost:80/", wgetCommand
          }

        mockS3Synchronizer.use {
            mockFileBasedTemplate.use {
                mockForApacheHost.use {
                    mockForTomcatServer.use {
                        mockAppServerTier.use {
                            host = new EC2Server();
                            def appServerTier = new AppServerTier()
                            tomcatServer = new TomcatServer()

                            apacheServer = new ApacheServer(host, appServerTier, spec)

                            apacheServer.configure()
                        }
                    }

                }
            }
        }
    }

}